#ifndef _DE_SMART_POINTER_H_
#define _DE_SMART_POINTER_H_
#include "PCH.h"
namespace DeviousRenderer
{

class DeRefCountedObject
{

public:

	DeRefCountedObject(): NumRefs(0) {}

	virtual ~DeRefCountedObject() { /*UtilityAssert(!NumRefs);*/ }

	DWORD AddRef() const
	{
		return DWORD(++NumRefs);
	}

	DWORD Release() const
	{
		DWORD Refs = DWORD(--NumRefs);
		if(Refs == 0)
		{
			delete this;
		}
		return Refs;
	}

	DWORD GetRefCount() const
	{
		return DWORD(NumRefs);
	}

private:
	mutable int NumRefs;

};





/**

* A smart pointer to an object which implements AddRef/Release.

*/

template<typename ReferencedType>
class TSmartPointer
{
	typedef ReferencedType* ReferenceType;
public:
	TSmartPointer():
	  Reference(NULL)
	  {}

	  TSmartPointer(ReferencedType* InReference,bool bAddRef = true)
	  {
		  Reference = InReference;
		  if(Reference && bAddRef)
		  {
			  Reference->AddRef();
		  }
	  }

	  TSmartPointer(const TSmartPointer& Copy)
	  {
		  Reference = Copy.Reference;
		  if(Reference)
		  {
			  Reference->AddRef();
		  }
	  }

	  ~TSmartPointer()
	  {
		  if(Reference)
		  {
			  Reference->Release();
		  }
	  }

	  TSmartPointer& operator=(ReferencedType* InReference)

	  {
		  // Call AddRef before Release, in case the new reference is the same as the old reference.
		  ReferencedType* OldReference = Reference;
		  Reference = InReference;
		  if(Reference)
		  {
			  Reference->AddRef();
		  }

		  if(OldReference)
		  {
			  OldReference->Release();
		  }
		  return *this;
	  }



	  TSmartPointer& operator=(const TSmartPointer& InPtr)
	  {
		  return *this = InPtr.Reference;
	  }



	  bool operator==(const TSmartPointer& Other) const
	  {
		  return Reference == Other.Reference;
	  }



	  ReferencedType* operator->() const
	  {
		  return Reference;
	  }



	  operator ReferenceType() const
	  {
		  return Reference;
	  }



	  ReferencedType** GetInitReference()
	  {
		  *this = NULL;
		  return &Reference;
	  }



	  ReferencedType* GetReference() const
	  {
		  return Reference;
	  }



	  friend bool IsValidRef(const TSmartPointer& Reference)
	  {
		  return Reference.Reference != NULL;
	  }
	  
	  void SafeRelease()
	  {
		  *this = NULL;
	  }
	  

	  DWORD GetRefCount()
	  {
		  if(Reference)
		  {
			  Reference->AddRef();
			  return Reference->Release();
		  }
		  else
		  {
			  return 0;
		  }
	  }



private:

	ReferencedType* Reference;

};

}
#endif //_DE_SMART_POINTER_H_